/**
 * MINAPL Code generator.
 * Copyright 2012 Michael A. Muller
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "CodeGen.h"

#include <malloc.h>
#include <string.h>
#include <unistd.h>

using namespace minapl;

CodeGen::CodeGen() :
    codeBuffer(0),
    curCode(0),
    codeSize(0),
    keyedData(4) {
}

CodeGen::~CodeGen() {
    free(codeBuffer);
}

void CodeGen::setKey(void *key, void *val) {
    keyedData.add(KeyVal(key, val));
}

void *CodeGen::getKey(void *key) {
    for (int i = 0; i < keyedData.size; ++i) {
        if (keyedData[i].key == key)
            return keyedData[i].val;
    }

    return 0;
}

void CodeGen::deleteKey(void *key) {

    int i;
    for (i = 0; i < keyedData.size; ++i) {
        if (keyedData[i].key == key)
            break;
    }

    // check if we didn't find it
    if (i == keyedData.size)
        return;

    // move everything after the found item down one (we shouldn't need
    // this in the common use case - items should be removed in the
    // reverse order that they were added)
    for (int j = i; j < keyedData.size - 1; ++j)
        keyedData.data[j] = keyedData[j + 1];
    --keyedData.size;
}

void CodeGen::need(int numBytes) {

    // see if we need to reallocate
    if (curCode - codeBuffer + numBytes >= codeSize) {

        // initialize codeSize
        if (!codeSize)
            codeSize = 1024;
        else
            codeSize *= 2;

        uint8_t *newCodeBuffer =
            (uint8_t *)memalign(getpagesize(), codeSize);
        if (codeBuffer)
            memcpy(newCodeBuffer, codeBuffer, curCode - codeBuffer);
        curCode = newCodeBuffer + (curCode - codeBuffer);
        free(codeBuffer);
        codeBuffer = newCodeBuffer;
    }
}
